/**
 * @file
 * @brief 板级描述层：初始化
 * @author
 * + 隐星魂 (Roy Sun) <xwos@xwos.tech>
 * @copyright
 * + Copyright © 2015 xwos.tech, All Rights Reserved.
 * > Licensed under the Apache License, Version 2.0 (the "License");
 * > you may not use this file except in compliance with the License.
 * > You may obtain a copy of the License at
 * >
 * >         http://www.apache.org/licenses/LICENSE-2.0
 * >
 * > Unless required by applicable law or agreed to in writing, software
 * > distributed under the License is distributed on an "AS IS" BASIS,
 * > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * > See the License for the specific language governing permissions and
 * > limitations under the License.
 */

#include "board/std.h"
#include <xwcd/soc/arm/v7m/arch_init.h>
#include <xwcd/soc/arm/v7m/m7/s32k3xx/soc_init.h>
#include <xwos/lib/xwbop.h>
#include <xwos/osal/skd.h>
#include <xwos/mm/bma.h>
#include <xwos/mm/mempool/allocator.h>
#include "RTD/mif.h"

extern xwu64_t sram_mr_origin[];
extern xwu64_t sram_mr_size[];

__xwbsp_init_code
void board_init_sram(void)
{
        xwu64_t * ram;
        xwsz_t size;
        xwsq_t i;

        ram = sram_mr_origin;
        size = (xwsz_t)sram_mr_size / sizeof(xwu64_t);

        for (i = 0; i < size; i++) {
                ram[i] = 0;
        }
}

extern xwu8_t cacheable_data_lma_base[];
extern xwu8_t cacheable_data_vma_base[];
extern xwu8_t cacheable_data_vma_end[];
extern xwu8_t cacheable_bss_vma_base[];
extern xwu8_t cacheable_bss_vma_end[];

__xwbsp_init_code
void board_relocate_cacheable_data(void)
{
        xwsz_t cnt, i;
        xwu8_t * src;
        xwu8_t * dst;

        src = cacheable_data_lma_base;
        dst = cacheable_data_vma_base;
        if (dst != src) {
                cnt = (xwsz_t)cacheable_data_vma_end - (xwsz_t)cacheable_data_vma_base;
                for (i = 0; i < cnt; i++) {
                        *dst = *src;
                        dst++;
                        src++;
                }
        }

        dst = cacheable_bss_vma_base;
        cnt = (xwsz_t)cacheable_bss_vma_end - (xwsz_t)cacheable_bss_vma_base;
        for (i = 0; i < cnt; i++) {
                *dst = 0;
                dst++;
        }
}

extern xwu8_t non_cacheable_data_lma_base[];
extern xwu8_t non_cacheable_data_vma_base[];
extern xwu8_t non_cacheable_data_vma_end[];
extern xwu8_t non_cacheable_bss_vma_base[];
extern xwu8_t non_cacheable_bss_vma_end[];

__xwbsp_init_code
void board_relocate_non_cacheable_data(void)
{
        xwsz_t cnt, i;
        xwu8_t * src;
        xwu8_t * dst;

        src = non_cacheable_data_lma_base;
        dst = non_cacheable_data_vma_base;
        if (dst != src) {
                cnt = (xwsz_t)non_cacheable_data_vma_end -
                      (xwsz_t)non_cacheable_data_vma_base;
                for (i = 0; i < cnt; i++) {
                        *dst = *src;
                        dst++;
                        src++;
                }
        }

        dst = non_cacheable_bss_vma_base;
        cnt = (xwsz_t)non_cacheable_bss_vma_end - (xwsz_t)non_cacheable_bss_vma_base;
        for (i = 0; i < cnt; i++) {
                *dst = 0;
                dst++;
        }
}

extern xwu8_t shareable_data_lma_base[];
extern xwu8_t shareable_data_vma_base[];
extern xwu8_t shareable_data_vma_end[];
extern xwu8_t shareable_bss_vma_base[];
extern xwu8_t shareable_bss_vma_end[];

__xwbsp_init_code
void board_relocate_shareable_data(void)
{
        xwsz_t cnt, i;
        xwu8_t * src;
        xwu8_t * dst;

        src = shareable_data_lma_base;
        dst = shareable_data_vma_base;
        if (dst != src) {
                cnt = (xwsz_t)shareable_data_vma_end - (xwsz_t)shareable_data_vma_base;
                for (i = 0; i < cnt; i++) {
                        *dst = *src;
                        dst++;
                        src++;
                }
        }

        dst = shareable_bss_vma_base;
        cnt = (xwsz_t)shareable_bss_vma_end - (xwsz_t)shareable_bss_vma_base;
        for (i = 0; i < cnt; i++) {
                *dst = 0;
                dst++;
        }
}

extern xwu8_t armv7m_ivt_lma_base[];
extern xwu8_t armv7m_ivt_vma_base[];
extern xwu8_t armv7m_ivt_vma_end[];

__xwbsp_init_code
void board_init_ivt(void)
{
        xwsz_t cnt, i;
        xwu8_t * src;
        xwu8_t * dst;

        src = armv7m_ivt_lma_base;
        dst = armv7m_ivt_vma_base;
        if (dst != src) {
                cnt = (xwsz_t)armv7m_ivt_vma_end - (xwsz_t)armv7m_ivt_vma_base;
                for (i = 0; i < cnt; i++) {
                        dst[i] = src[i];
                }
        }
        armv7m_scs.scb.vtor.u32 = (xwu32_t)dst;
}


extern xwsz_t heap_mr_origin[];
extern xwsz_t heap_mr_size[];
__xwbsp_data struct xwmm_mempool * heap_mempool = (void *)heap_mr_origin;

extern xwsz_t dtcmheap_mr_origin[];
extern xwsz_t dtcmheap_mr_size[];
__xwbsp_data XWMM_BMA_DEF(dtcmheap_bma_raw, BRDCFG_MM_DTCMHEAP_BLKODR);
__xwbsp_data struct xwmm_bma * dtcmheap_bma = (void *)&dtcmheap_bma_raw;

extern xwsz_t irq_memory_size[];

__xwbsp_init_code
void board_init_cpu0_mm(void)
{
        xwer_t rc;
        xwssq_t odr;
        void * sysmem;

        /* 初始化 HEAP 内存区域的内存池 */
        odr = xwbop_fls(xwsz_t, (xwsz_t)heap_mr_size / XWMM_MEMPOOL_PAGE_SIZE);
        rc = xwmm_mempool_init(heap_mempool, "HEAP",
                               (xwptr_t)heap_mr_origin,
                               (xwsz_t)heap_mr_size,
                               (xwsz_t)odr,
                               0U,
                               NULL);
        if (rc < 0) {
                XWOS_BUG();
        }

        /* 初始化 DTCM HEAP 内存区域的伙伴算法分配器 */
        rc = xwmm_bma_init(dtcmheap_bma, "dtcmheap",
                           (xwptr_t)dtcmheap_mr_origin, (xwsz_t)dtcmheap_mr_size,
                           BRDCFG_MM_DTCMHEAP_BLKSZ, BRDCFG_MM_DTCMHEAP_BLKODR);
        if (rc < 0) {
                XWOS_BUG();
        }

        /* 申请系统预留内存，用于重定向中断向量表，以及作为中断函数的栈 */
        odr = xwbop_fls(xwsz_t, (xwsz_t)irq_memory_size / BRDCFG_MM_DTCMHEAP_BLKSZ);
        rc = xwmm_bma_alloc(dtcmheap_bma, (xwsq_t)odr, &sysmem);
        if (rc < 0) {
                XWOS_BUG();
        }
}

__xwbsp_init_code
void board_init_cpu1_mm(void)
{
        xwer_t rc;
        xwssq_t odr;
        void * sysmem;

        /* 初始化 DTCM HEAP 内存区域的伙伴算法分配器 */
        rc = xwmm_bma_init(dtcmheap_bma, "dtcmheap",
                           (xwptr_t)dtcmheap_mr_origin, (xwsz_t)dtcmheap_mr_size,
                           BRDCFG_MM_DTCMHEAP_BLKSZ, BRDCFG_MM_DTCMHEAP_BLKODR);
        if (rc < 0) {
                XWOS_BUG();
        }

        /* 申请系统预留内存，用于中断栈 */
        odr = xwbop_fls(xwsz_t, (xwsz_t)irq_memory_size / BRDCFG_MM_DTCMHEAP_BLKSZ);
        rc = xwmm_bma_alloc(dtcmheap_bma, (xwsq_t)odr, &sysmem);
        if (rc < 0) {
                XWOS_BUG();
        }
}

extern void SystemInit(void);

__xwbsp_init_code
void xwos_preinit(void)
{
        xwid_t cpuid;

        arch_init();
        soc_init();

        cpuid = xwos_skd_get_cpuid_lc();
        switch (cpuid) {
        case 0:
                board_init_sram();
                board_relocate_cacheable_data();
                board_relocate_non_cacheable_data();
                board_relocate_shareable_data();
                board_init_cpu0_mm();
                board_init_ivt(); /* 在刚申请的内存区域重定向中断向量表 */
                break;
        case 1:
                board_init_cpu1_mm();
                board_init_ivt(); /* 在刚申请的内存区域重定向中断向量表 */
                break;
        default:
                XWOS_BUG();
        }
        SystemInit();
}

__xwbsp_init_code
void xwos_postinit(void)
{
        xwid_t cpuid;
        cpuid = xwos_skd_get_cpuid_lc();
        if (0 == cpuid) {
                rtd_init();
        }
}
